///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_MAT_DETAIL_CTRIANGULARVIEW_H_
#define _BUOLA_MAT_DETAIL_CTRIANGULARVIEW_H_

#include <buola/mat/cexpr.h>
#include <buola/mat/detail/eigen_wrapper.h>

namespace buola { namespace mat { namespace detail {

template<typename tSub,typename tMode>
struct MMatrixTraits<CTriangularView<tSub,tMode>>
{
private:
    typedef MMatrixTraits<ODecay<tSub>> TSubTraits;

public:
    typedef typename TSubTraits::TScalar TScalar;
    static const size_t cRows=TSubTraits::cRows;
    static const size_t cCols=TSubTraits::cCols;
    static const bool cRowLinearAccess=TSubTraits::cRowLinearAccess;
    static const bool cColLinearAccess=TSubTraits::cColLinearAccess;
    static const bool cRowPacketAccess=TSubTraits::cRowPacketAccess;
    static const bool cColPacketAccess=TSubTraits::cColPacketAccess;
    static const bool cMightAlias=false;
    static const int cElementAccess=TSubTraits::cElementAccess;
    static const bool cEigenMappable=TSubTraits::cEigenMappable;
    static const bool cKeepConstness=false;
    static const bool cExprAssignable=false;
    static const bool cIsMatrix=false;
};

template<typename tMode>
struct CEigenTriangularMode;

template<>
struct CEigenTriangularMode<NUpper>
{
    static const unsigned int value=Eigen::Upper;
};

template<>
struct CEigenTriangularMode<NLower>
{
    static const unsigned int value=Eigen::Lower;
};

template<typename tSub,typename tMode>
class CTriangularView : public CExpr<CTriangularView<tSub,tMode>>
{
    typedef MMatrixTraits<CTriangularView<tSub,tMode>> TSelfTraits;

public:
    CTriangularView(tSub pSub)
        :   mSub(pSub)
    {}
    
    template<typename... tArgs>
    CTriangularView(NConstructSub,tArgs&&... pArgs)
        :   mSub(std::forward<tArgs>(pArgs)...)
    {}

    CTriangularView(const CTriangularView&)=delete;
    CTriangularView& operator=(const CTriangularView&)=delete;

    size_t Rows() const  {   return mSub.Rows(); }
    size_t Cols() const  {   return mSub.Cols(); }

    template<typename tType>
    tType At(size_t r,size_t c) const       {   return mSub.template At<tType>(r,c);    }
    template<typename tType>
    tType At(size_t i) const                {   return mSub.template At<tType>(i);    }

    typename TSelfTraits::TScalar *Data()           {   return mSub.Data(); }
    const typename TSelfTraits::TScalar *Data() const     {   return mSub.Data(); }
    
    template<typename tDerived>
    OMatrixType<tDerived> Solve(const CExpr<tDerived> &pExpr)
    {
        OMatrixType<tDerived> lResult(nSize,pExpr.Derived().Rows(),pExpr.Derived().Cols());
        eigen_map(lResult)=eigen_map(eigen_mappable(mSub)).template triangularView<CEigenTriangularMode<tMode>::value>().
                                                        solve(eigen_map(eigen_mappable(pExpr.Derived())));
        return lResult;
    }
    
private:
    tSub mSub;
};

/*namespace detail*/ } /*namespace mat*/ } /*namespace buola*/ }

#endif
